﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.WebApi.Extensions
 * 唯一标识：62f0aa6f-12ae-4c2c-b3c9-a7303e948d06
 * 文件名：VampirewalCoreWebApiExtension
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2023/9/27 12:30:14
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>

namespace Vampirewal.Core.WebApi;

/// <summary>
///
/// </summary>
public static class VampirewalCoreWebApiExtension
{
    /// <summary>
    /// 启用WebApi监听功能
    /// <para><paramref name="默认监听端口号9999"></paramref></para>
    /// </summary>
    /// <param name="services"></param>
    /// <param name="config"></param>
    public static void UseVampirewalWebApi(this IServiceCollection services, Action<VampirewalCoreWebApiConfig> config)
    {
        services.AddVampirewalControllers();

        VampirewalCoreWebApiConfig Config = VampirewalCoreWebApiConfig.InitConfig();
        config?.Invoke(Config);

        services.AddSingleton(Config);

        foreach (var item in Config.Services)
        {
            services.Add(item);
        }

        if (!IsFirst)
        {
            services.AddVampirewalApiResultProvider<VampirewalApiResultProvider>();
        }

        services.AddSingleton<IVampirewalMiddleware, VampirewalRoutingMiddleware>();
    }

    internal static List<ApiDocControllerInfo> ApiDocInfos { get; set; } = new List<ApiDocControllerInfo>();

    /// <summary>
    /// 将标记<typeparamref name="VampirewalControllerAttribute"/>特性的类注册进<typeparamref name="IServiceCollection"/>中
    /// </summary>
    /// <param name="Services"></param>
    private static void AddVampirewalControllers(this IServiceCollection Services)
    {
        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(w => w.GetCustomAttribute<VampirewalControllerAttribute>() != null).ToArray();

        foreach (var type in types)
        {
            var Attribute = type.GetCustomAttribute<VampirewalControllerAttribute>();

            if (Attribute != null)
            {
                ApiDocControllerInfo controller = new ApiDocControllerInfo()
                {
                    Methods = new List<ApiDocMethodInfo>(),
                    Name = Attribute.ControllerName,
                    ControllerName = type.Name,
                    Description = Attribute.Description,
                };

                switch (Attribute.registerType)
                {
                    case RegisterType.Singleton:
                        Services.TryAddSingleton(type);
                        break;

                    case RegisterType.Transient:
                        Services.TryAddTransient(type);
                        break;

                    case RegisterType.Scoped:
                        Services.TryAddScoped(type);
                        break;
                }

                var methods = type.GetMethods();
                foreach (var method in methods)
                {
                    var routeAttr = method.GetCustomAttribute<VampirewalHttpAttribute>();
                    if (routeAttr != null)
                    {
                        if (routeAttr.RoutePath.StartsWith("/"))
                        {
                            throw new Exception($"Controller:{type.FullName}中的Method:{method.Name}的RoutePath，开头不能有/");
                        }

                        if (!routeAttr.ApiDocHidde)
                        {
                            ApiDocMethodInfo methodInfo = new ApiDocMethodInfo()
                            {
                                Name = routeAttr.MethodName,
                                Description = routeAttr.Description,
                                HttpType = routeAttr.Method,
                                RoutePath = routeAttr.RoutePath,
                                Parameters = new List<ApiDocMethodParameter>()
                            };

                            var Params = method.GetParameters();
                            foreach (var param in Params)
                            {
                                ApiDocMethodParameter par = new ApiDocMethodParameter()
                                {
                                    Name = param.Name,
                                    Description = param.GetCustomAttribute<VampirewalParameterAttribute>()?.Description,
                                    Type = param.ParameterType.Name
                                };

                                methodInfo.Parameters.Add(par);
                            }

                            controller.Methods.Add(methodInfo);
                        }

                        Routes.Add(routeAttr.RoutePath, (type, method));
                    }
                }

                if (!Attribute.ApiDocHidde)
                {
                    ApiDocInfos.Add(controller);
                }
            }
        }
    }

    /// <summary>
    /// 注册VampirewalMiddleware中间件
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="config"></param>
    /// <returns></returns>
    public static VampirewalCoreWebApiConfig AddVampirewalMiddleware<T>(this VampirewalCoreWebApiConfig config) where T : class, IVampirewalMiddleware
    {
        config.Services.AddSingleton<IVampirewalMiddleware, T>();
        return config;
    }

    internal static Dictionary<string, (Type Controller, MethodInfo Method)> Routes { get; } = new();

    internal static bool IsFirst { get; private set; } = false;

    /// <summary>
    /// 注册全局API结果返回值
    /// <para><paramref name="框架已添加默认返回值拦截"></paramref></para>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="services"></param>
    /// <returns></returns>
    public static IServiceCollection AddVampirewalApiResultProvider<T>(this IServiceCollection services) where T : class, IVampirewalApiResultProvider
    {
        if (!IsFirst)
        {
            services.AddSingleton<IVampirewalApiResultProvider, T>();
            IsFirst = true;
        }

        return services;
    }
}